package com.atguigu.zy.interview.juc.volatiles;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Jungle
 * @create 2023-08-30 11:42
 * 注释
 */
class MyData {
     volatile int number = 0;

    public void addTo60() {
        this.number = 60;
    }

    //请注意，此时number 前面是加了volatile 关键字修饰的，volatile不保证原子性
    //使用 synchronized 太重量级了
    public void addPlusPlus() {
        number++;
    }
    AtomicInteger atomicInteger=new AtomicInteger();

    public void addMyAtomic() {
        atomicInteger.getAndIncrement();
    }
}

/**
 * @author Jungle
 * 1、 验证volatile的可见性
 * 1.1 如 int number = 0;number变量之前根本没有添加volatile关键字修饰
 * 1.2 添加了volatile可以解决可见性问题。
 * 2、验证volatile不保证原子性
 * 2.1 原子性指的是什么意思？
 * 不可分割，完整性，也即某个线程正在做某个具体业务时，中间不可以被加塞或者被分割。需要整体完整，要么同时成功，要么同时失败。
 * 2.2 volatile是否可以保证原子性
 * 2.3 why
 * 2.4 如何解决原子性
 *      1、加sync
 *      2、使用AtomicInteger
 */
@Slf4j
public class VolatileDemo {
    public static void main(String[] args) {
        atomicVerify();
        // seeOkByVolatile();

    }

    /**
     * 测试原子性（不保证原子性）
     */
    private static void atomicVerify() {
        MyData myData = new MyData();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        for (int i = 1; i <= 20; i++) {
            new Thread(() -> {
                for (int j = 1; j <= 1000; j++) {
                    myData.addPlusPlus();
                    myData.addMyAtomic();
                }
            }, String.valueOf(i)).start();
        }

        //等待上面的结果全部执行完
        //数字2  main线程+守护线程  大于2说明有其他的线程
        while (Thread.activeCount() > 2) {
            //作用是让步，让当前线程由“运行状态”进入到“就绪状态”，从而让其它具有相同优先级的等待线程获取执行权
            Thread.yield();
        }

        log.info("执行时间==>{}",stopWatch.getTotalTimeMillis());

        System.out.println(Thread.currentThread().getName() + "\t int type finally number value:" + myData.number);
        System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type finally number value:" + myData.atomicInteger.get());
    }

    //volatile可以保证可见性，及时通知其他线程，主物理内容中的值已经被修改
    private static void seeOkByVolatile() {
        //线程操纵资源类
        MyData myData = new MyData();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t content");

            //@formatter:off  线程暂停一会儿
            try { TimeUnit.SECONDS.sleep( 3 ); } catch (InterruptedException e) { e.printStackTrace();}
            myData.addTo60();
            //@formatter:on
            System.out.println(Thread.currentThread().getName() + "\t update number value:" + myData.number);
        }, "AAA").start();


        //    第二个线程是我们的main线程
        while (myData.number == 0) {
            //main线程就一直再这里等待循环，直到humber值不再等于零
        }
        System.out.println(Thread.currentThread().getName() + "\t mission is over,main get number value:" + myData.number);
    }
}
